﻿using System;
using System.Collections.Generic;
using System.Text;

namespace CompilerPhase4
{
    public class Interpreter
    {
        #region FIELDS
        int PC, opcode;
        #endregion

        public Interpreter()                            //Constructor (default)
        {

        }
/*-----------------------------------------------------------------------------
         * InterpretQuads: Takes the next quad in the cycle and processes it  |
         * in accordance to its opcode and op1, op2, op3 values.              |
 *---------------------------------------------------------------------------*/
        public void InterpretQuads(QuadTable q, SymbolTable s, bool TraceOn)
        {
            Quad currentOp;                              //Holds the current Op
            PC = 0;                                        //Initialize PC to 0
            const int MAXQUAD = 1000;            //Set a max for the quad table
            while (PC < MAXQUAD)  //while PC is less than the max index of quad
            {
                currentOp = q.GetQuad(PC);      //Get the next Op from QuadTable
                Quad saveOp = currentOp; //Quad to stay unchanged to save values

                if (currentOp.Opcode < 16 || currentOp.Opcode > 0) //Check valid
                {
                    opcode = currentOp.Opcode;                      //Set opcode
                    switch (opcode)
                    {
                        #region ARITHMETIC OpERATORS
                        case 1:                                            //DIV
                            currentOp.Op3 = (currentOp.Op1 / currentOp.Op2);                  
                                                              //Execute division
                            PC++;                                 //Increment PC
                            break;
                        case 2:                                            //MUL
                            currentOp.Op3 = currentOp.Op1 * currentOp.Op2; 
                                                        //Execute multiplication
                            PC++;                                 //Increment PC
                            break;
                        case 3:                                            //SUB
                            currentOp.Op3 = currentOp.Op1 - currentOp.Op2;
                                                           //Execute subtraction
                            PC++;                                 //Increment PC
                            break;
                        case 4:                                            //ADD
                            currentOp.Op3 = currentOp.Op1 + currentOp.Op2;          
                                                              //Execute addition
                            PC++;                                 //Increment PC
                            break;
                        #endregion
                        case 5:                                         //ASSIGN
                            currentOp.Op3 = currentOp.Op1;
                                       //Assign currentOp.op1 into currentOp.op3
                            break;
                        #region BRANCH currentOp.OpERATORS
                        case 6:                                            //BNZ
                            if (currentOp.Op1 != 0)
                            {               //If currentOp.op1 is not equal to 0
                                PC = currentOp.Op3;
                            }                 //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 7:                                           //BNP
                            if (currentOp.Op1 <= 0)
                            {                //If currentOp.op1 is not positive
                                PC = currentOp.Op3;
                            }                //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 8:                                           //BNN
                            if (currentOp.Op1 >= 0)
                            {                 //If currentOp.op1 is not negative
                                PC = currentOp.Op3;
                            }                 //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 9:                                            //BZ
                            if (currentOp.Op1 == 0)     //If currentOp.op1 == 0
                            {
                                PC = currentOp.Op3;
                            }                //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 10:                                           //BP
                            if (currentOp.Op1 > 0)
                            {                    //If currentOp.op1 is positive
                                PC = currentOp.Op3;
                            }                //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 11:                                           //BN
                            if (currentOp.Op1 < 0)
                            {                     //If currentOp.op1 is negative
                                PC = currentOp.Op3;
                            }                 //Branch to value of currentOp.op3
                            else
                            {
                                PC++;            //Otherwise, just increment PC
                            }
                            break;
                        case 12:                                           //BR
                            PC = currentOp.Op3;
                            break;    //Unconditionally branch to currentOp.op3
                        case 13:                                        //BINDR
                            PC = currentOp.Op3;
                            break;    //Unconditionally branch to currentOp.op3
                        #endregion
                        case 14:                               //STcurrentOp.Op
                            Console.WriteLine("Execution terminated by " + 
                            "program.");    //Alert user to program termination
                            PC = MAXQUAD;     //Set PC to termination condition
                            break;
                        case 15:                                        //PRINT
                            if (currentOp.GetOp1().Type != 1)
                            {    /*If printing a label, omit printing int value
                                  * because it's not pertinent*/
                                Console.WriteLine(currentOp.GetOp1().Name + 
                                    " = " + currentOp.Op1.ToString());
                                                //Name and val of currentOp.op1
                            }
                            else
                            {
                                Console.WriteLine(currentOp.GetOp1().Name);
                            }
                            PC++;
                            break;
                    }                                              //END SWITCH
                }                                                      //END IF
                if (TraceOn == true)   //If user desires a trace of the program
                {
                    int printPC;
                    if (opcode != 14)
                    {
                        printPC = PC - 1;
                    }
                    else
                    {
                        printPC = PC;
                    }
                    Console.WriteLine("Trace:\tPC: " + printPC.ToString() +
                    ",\tExecuting: " + q.GetMnemonic(opcode).ToString() + ", "
                    + currentOp.GetOp1().Value.ToString() + ", " + 
                    currentOp.GetOp2().Value.ToString() + ", "
                    + currentOp.GetOp3().Value.ToString());
                     //Print trace label, PC value, operation, and all operands
                }
            }                                            //END IF(VALID OPCODE)
        }                                                           //END WHILE
/*---------------------------------------------------------------------------*/
    }
}
